﻿#pragma once
#include"RBTree.h"
namespace celia
{

//成绩相关的宏
//选科相关
#define ENGLISH (((size_t)1) << (63))
#define MATH (((size_t)1) << (62))
#define SPORT (((size_t)1) << (61))
#define POLITICS (((size_t)1) << (60))
//判断是否选科
#define _HAVE_ENGLISH_(x) ((x) & (ENGLISH))
#define _HAVE_MATH_(x) ((x) & (MATH))
#define _HAVE_SPORT_(x) ((x) & (SPORT))
#define _HAVE_POLITICS_(x) ((x) & (POLITICS))
//每个科目成绩的位置
#define _ENGLISH_POS_ ((size_t)(0xFF))
#define _MATH_POS_ ((size_t)(0xFF00))
#define _SPORT_POS_ ((size_t)(0xFF0000))
#define _POLITICS_POS_ ((size_t)(0xFF000000))
//获取成绩
#define _GET_ENGLISH_GRADE_(x) (((x) & (_ENGLISH_POS_)) >> 0)
#define _GET_MATH_GRADE_(x) (((x) & (_MATH_POS_)) >> 8)
#define _GET_SPORT_GRADE_(x)(((x) & (_SPORT_POS_)) >> 16)
#define _GET_POLITICS_GRADE_(x)(((x) & (_POLITICS_POS_)) >> 24)
//对数据进行移动
#define _MOVE_POS_ENGLISH_(x) ((_ENGLISH_POS_) & ((size_t)x << 0))
#define _MOVE_POS_MATH_(x) ((_MATH_POS_) & ((size_t)x << 8))
#define _MOVE_POS_SPORT_(x) ((_SPORT_POS_) & ((size_t)x << 16))
#define _MOVE_POS_POLITICS_(x) ((_POLITICS_POS_) & ((size_t)x << 24))


	//所有类和重载函数的前置声明
	enum Gender;
	enum Healthy;
	enum Political;
	struct HomeInfo;
	struct PersonInfo;
	struct SchInfo;
	struct ResumeInfo;
	struct Reward;
	struct TeachInfo;
	class Grade;
	class StuInfo;
	class StuFiles;
	class Date;

	
	std::ostream& operator<<(std::ostream& out, const Date& date);
	std::istream& operator>>(std::istream& in, Date& date);
	std::ostream& operator<<(std::ostream& out, celia::Reward& reward);
	std::ostream& operator<<(std::ostream& out, celia::ResumeInfo& resume);
	std::ostream& operator<<(std::ostream& out, celia::TeachInfo& teach);
	std::ostream& operator<<(std::ostream& out, celia::StuInfo& stu);



	//日期类
	class Date
	{
		friend std::ostream& operator<<(std::ostream& out, const Date& date);
		friend std::istream& operator>>(std::istream& in, Date& date);
	public:
		void Print()
		{
			std::cout << _year << '/' << _month << '/' << _day << std::endl;
		}
		//获取当前的月份天数
		int GetMonthDay(int year, int month)
		{
			static int Month[13] = { -1,31,28,31,30,31,30,31,31,30,31,30,31 };
			if (month == 2 && ((year % 400 == 0) || (year % 4 == 0 && year % 100 != 0)))
			{
				return 29;
			}
			else
				return Month[month];
		}
		//构造函数
		Date(int year = 2000, int month = 6, int day = 1)
			:_year(year),
			_month(month),
			_day(day) {}
		//析构函数 不用写
		~Date() {}
		//拷贝构造函数
		Date(const Date& date)
		{
			_year = date._year;
			_month = date._month;
			_day = date._day;
		}
		/*===========================================================================*/
			// 日期+=天数
		Date& operator+=(int day);
		// 日期+天数
		Date operator+(int day);
		// 日期-天数
		Date operator-(int day);
		// 日期-=天数
		Date& operator-=(int day);
		// 前置++
		Date& operator++();
		// 后置++
		Date operator++(int);
		// 后置--
		Date operator--(int);
		// 前置--
		Date& operator--();
		// >运算符重载
		bool operator>(const Date& d)const;
		// ==运算符重载
		bool operator==(const Date& d)const;
		// >=运算符重载
		bool operator >= (const Date& d)const;
		// <运算符重载
		bool operator < (const Date& d)const;
		// <=运算符重载
		bool operator <= (const Date& d)const;
		// !=运算符重载
		bool operator != (const Date& d)const;
		// 日期-日期 返回天数
		int operator-(const Date& d)const;


		//赋值运算符重载
		Date& operator=(const Date& date)
		{
			_day = date._day;
			_month = date._month;
			_year = date._year;

			return *this;
		}

	private:
		int _year;
		int _month;
		int _day;

	};

	//重载输出
	std::ostream& operator<<(std::ostream& out, const Date& date);
	//重载输入
	std::istream& operator>>(std::istream& in, Date& date);

	Date& Date::operator+=(int day)
	{
		_day += day;
		while (_day > GetMonthDay(_year, _month))
		{
			_day -= GetMonthDay(_year, _month);
			++_month;
			if (_month == 13)
			{
				_year++;
				_month = 1;
			}
		}
		return *this;
	}
	Date& Date::operator-=(int day)
	{
		_day -= day;
		while (_day <= 0)
		{
			_day += GetMonthDay(_year, (_month - 1) == 0 ? 12 : (_month - 1));
			--_month;
			if (_month == 0)
			{
				_year--;
				_month = 12;
			}
		}
		return *this;
	}

	// 日期+天数
	Date Date::operator+(int day)
	{
		Date date = *this;
		date += day;
		return date;
	}
	// 日期-天数
	Date Date::operator-(int day)
	{
		Date date = *this;
		date -= day;
		return date;
	}
	// 前置++
	Date& Date::operator++()
	{
		*this += 1;
		return *this;
	}
	// 后置++
	Date Date::operator++(int)
	{
		Date date = *this;
		date += 1;
		return date;
	}
	// 后置--
	Date Date::operator--(int)
	{
		Date date = *this;
		date -= 1;
		return date;
	}
	// 前置--
	Date& Date::operator--()
	{
		*this -= 1;
		return *this;
	}
	// >运算符重载
	bool Date::operator>(const Date& d)const
	{
		if (_year > d._year)
		{
			return true;
		}
		else if (_year == d._year)
		{
			if (_month > d._month)
			{
				return true;
			}
			else if (_month == d._month)
				return _day > d._day;
		}

		return false;
	}
	// ==运算符重载
	bool Date::operator==(const Date& d)const
	{
		return _year == d._year && _month == d._month && _day == d._day;
	}
	// >=运算符重载
	bool Date::operator >= (const Date& d)const
	{
		return *this == d || *this > d;
	}
	// <运算符重载
	bool Date::operator < (const Date& d)const
	{
		return !(*this >= d);
	}
	// <=运算符重载
	bool Date::operator <= (const Date& d)const
	{
		return !(*this > d);
	}
	// !=运算符重载
	bool Date::operator != (const Date& d)const
	{
		return !(*this == d);
	}
	// 日期-日期 返回天数
	int Date::operator-(const Date& d)const
	{
		int n = 0;
		int flg = 1;

		Date max = *this;
		Date min = d;
		if (min > max)
		{
			max = d;
			min = *this;
			flg = -1;
		}
		while (min != max)
		{
			min += 1;
			n++;
		}
		return n * flg;
	}

	std::ostream& operator<<(std::ostream& out, const Date& date)
	{
		out << date._year << "年" << date._month << "月" << date._day << "日" << std::endl;
		return out;
	}

	std::istream& operator>>(std::istream& in, Date& date)
	{
		std::cout << "请输入年、月、日：";
		in >> date._year >> date._month >> date._day;
		return in;
	}

	/*=========================================================================================================================*/
	//一些枚举类型
	enum Gender //性别
	{
		MALE,
		FEMALE
	};
	enum Healthy //健康状况
	{
		EXXCELLENT,
		GOOD,
		GENERAL,
		WEEK
	};
	enum Political  //政治面貌
	{
		LEAGUE_MEMBER,
		PARTY_MEMBER,
		GENERAL_PUBLIC
	};
	/*=========================================================================================================================================*/
	//描述学生的信息类
	struct HomeInfo
	{
		HomeInfo(const std::string& address, const std::string& fam_phone)
			:_address(address), _family_phone(fam_phone)
		{}
		std::string _address; //家庭住址
		std::string _family_phone; //家庭电话
	};
	struct PersonInfo
	{
		PersonInfo(const Date& birth, const std::string& name, const Gender& gender, const std::string& nation, \
			const std::string& native, const std::string& phone, const Healthy& health, size_t age)
			:_birth(birth), _name(name), _gender(gender), _nationality(nation)
			, _native_place(native), _phone(phone), _health_state(health), _age(age)
		{}
		Date _birth; //出生年月
		std::string _name; //姓名
		Gender _gender; //性别
		size_t _age;
		std::string _nationality; //民族
		std::string _native_place; //籍贯
		std::string _phone; //移动电话
		Healthy _health_state; //健康状态
	};
	struct SchInfo
	{
		SchInfo(const std::string& school, const Date& join_time, const std::string& college, \
			const std::string& major, const std::string& school_flg, const Political& political, \
			const Date& join_political_time, const std::string& hostel_flg, const std::string& hostel_phone, \
			const std::string& post, const Date& post_time)
			:_school(school), _join_time(join_time), _college(college), _major(major), _school_flg(school_flg)
			, _political(political), _join_political_time(join_political_time), _hostel_flg(hostel_flg), _hostel_phone(hostel_phone)
			, _post(post), _post_time(post_time)
		{}
		std::string _school;//所在学校
		Date _join_time; //入学时间
		std::string _college; //所在学院
		std::string _major; //所学专业
		std::string _school_flg; // 学号
		Political _political; //政治面貌
		Date _join_political_time; //加入党/团员时间
		std::string _hostel_flg; //宿舍号
		std::string _hostel_phone; //宿舍电话
		std::string _post; //职务
		Date _post_time; //职务时间
	};
	struct ResumeInfo
	{
		ResumeInfo(const std::string& school_flg, const Date& join_time, const std::string& school, \
			const std::string& post, const std::string& witness)
			:_school_flg(school_flg), _join_time(join_time), _school(school), _post(post), _witness(witness)
		{}
		std::string _school_flg; // 学号
		Date _join_time; //入学时间
		std::string _school;//所在学校
		std::string _post; //职务
		std::string _witness; //证明人
	};
	struct Reward
	{
		Reward(const std::string& school_flg, const Date& reward_time, const std::string& reason, \
			const std::string& reward)
			:_school_flg(school_flg), _reward_time(reward_time), _reason(reason), _reward(reward)
		{}
		std::string _school_flg; // 学号
		Date _reward_time; //奖励时间 
		std::string _reason; //奖励原因
		std::string _reward; //具体奖励
	};
	struct TeachInfo
	{
		TeachInfo(const std::string& school_flg, const std::string& lesson_name, const std::string& term,\
				  const size_t grade, const std::string& teacher)
			:_school_flg(school_flg), _lesson_name(lesson_name), _term(term), _grade(grade),
			_teacher(teacher)
		{}
		std::string _teacher;
		std::string _school_flg;
		std::string _lesson_name;
		std::string _term; //学期
		size_t _grade;
	};
	class Grade
	{
	public:
		void SetMajor(size_t grade) { _Major = grade; }
		void SetGrade(size_t POS) { _POS = POS; }
		size_t GetPOS() { return _POS; }
		size_t GetMajor() { return _Major; }
	private:
		size_t _POS = 0;
		size_t _Major = 0; //专业课必选
	};
	/*==================================================暂时完整=========================================================================*/
	
	/*
	*  1.输出内容需完善 OK
	*  2.结构体不足的部分补充 OK
	*  3.查询方式的完善  -->  学号-->姓名关系转换表？ OK
	*  4.按专业分类？（很难考虑....时间不够不打算做了， 寄.........）NONONONONO
	*  5.提前输入姓名，按照姓名分配学号？ ----> 录入修改、重新描述学生类 NONONONO
	*  6.实现红黑树的迭代器，并重写Insert、Erase函数的返回值  OK
	*  7.在删除后导入到历史记录中（如果有的话）（如果可以，加个时间？）OK
	*  8.按需求进行相应模块的输出:全部信息， 档案... OK
	*  9.学生信息的专业分类部分忘做了... NONONONONONO
	*  10.进行一下录入操作之前的专业种类输入？ NONONONO
	*  11.按照专业种类搞个vector？  NONONONONO
	*  12.Shell的私有变量可能要重新设计，关于专业分类 NONONONO
	*  13.红黑树的拷贝？ 赋值重载？ 外部架构的拷贝？ 赋值重载？ 
	*  14.关于奖惩，添加相应接口 OK
	*  15.历史记录应是可查找的 OK
	*/
	
	
	//单个学生信息结构 -----> 描述出来
	class StuInfo
	{
		friend class StuFiles;
		friend std::ostream& operator<<(std::ostream& out, celia::StuInfo& stu);

	public:
		StuInfo(const HomeInfo& homeInfo, const PersonInfo& personInfo, const SchInfo& schInfo, \
		const ResumeInfo& resumeInfo, const Grade& grade)
			:_homeInfo(homeInfo),_personInfo(personInfo), _schInfo(schInfo), _resumeInfo(resumeInfo), _grade(grade)
		{}
		void SetGrade(size_t POS)
		{
			_grade.SetGrade(POS);
		}
		void SetTeach(const TeachInfo& teachInfo)
		{
			_teachList.push_back(teachInfo);
		}
		void SetReward(const Reward& rewardInfo)
		{
			_rewardList.push_back(rewardInfo);
		}
	private:
		HomeInfo _homeInfo;
		PersonInfo _personInfo;
		SchInfo _schInfo;
		ResumeInfo _resumeInfo;
		//成绩部分
		Grade _grade;
		std::vector<Reward> _rewardList;
		std::vector<TeachInfo> _teachList;
	};




	//把描述的学生结构再进行组织，封装进红黑树中
	class StuFiles
	{
		typedef StuInfo Val;
		typedef std::string Key;
		struct KeyOfV
		{
			std::string operator()(const Val& stu)
			{
				return stu._schInfo._school_flg;
			}
		};
	public:
		bool Insert(const Val& stuInfo)
		{
			auto flg = _tree.Insert(stuInfo);
			return flg.second;
		}
		bool History_Insert(const Val& stuInfo)
		{
			auto flg = _history_tree.Insert(stuInfo);
			return flg.second;
		}
		bool Erase(const Key& del)
		{
			bool flg = _tree.Erase(del);
			return flg;
		}
		bool History_Erase(const Key& del)
		{
			bool flg = _history_tree.Erase(del);
			return flg;
		}
		void Inorder()
		{
			_tree.Inorder();
		}
		void Inorder(int)
		{
			auto it = _tree.begin();
			while (it != _tree.end())
			{
				std::cout << (*it)._resumeInfo << std::endl;
				++it;
			}
		}
		void Inorder(const Key& Message, int choice)
		{
			if (choice == 1)
			{
				auto it = _tree.begin();
				while (it != _tree.end())
				{
					if ((*it)._schInfo._major == Message)
					{
						std::cout << *it;
					}
					++it;
				}
			}
			else if (choice == 2)
			{
				auto it = _tree.begin();
				while (it != _tree.end())
				{
					if ((*it)._personInfo._native_place == Message)
					{
						std::cout << *it;
					}
					++it;
				}
			}
			else if (choice == 3)
			{
				RBTreeNode<Val>* ret = _tree.Find(Message);
				if (ret)
					std::cout << ret->_val << std::endl;
				else
					std::cout << "未找到该同学！" << std::endl;
			}
		}

		StuInfo* Find(const Key& key)
		{
			RBTreeNode<Val>* ret =  _tree.Find(key);
			if (ret)
				return &(ret->_val);
			else
				return nullptr;
		}
		//判断是否是一颗红黑树
		bool isBalance() { return _tree.isBalance(); }
		size_t TreeSize()
		{
			return _tree.Size();
		}
		size_t History_TreeSize()
		{
			return _history_tree.Size();
		}
		void InorderHistory()
		{
			_history_tree.Inorder();
		}
	private:
		celia::RBTree<std::string, celia::StuInfo, KeyOfV> _tree;
		celia::RBTree<std::string, celia::StuInfo, KeyOfV> _history_tree;
	};


//这里是一些成员的重载输出
#define GetHealth(health) (health == 0 ? "优秀" : (health == 1 ? "良好" : (health == 2 ? "一般" : "虚弱")))
#define GetGender(gender) (gender == 0 ? "男" : "女")
#define GetPolitical(political) (political == 0 ? "团员" : (political == 1 ? "党员" : "群众"))
	std::ostream& operator<<(std::ostream& out, celia::Reward& reward)
	{
		out << "奖惩学生学号：" << reward._school_flg << std::endl\
			<< "奖励/惩罚时间：" << reward._reward_time << std::endl\
			<< "奖励/惩罚原因：" << reward._reason << std::endl\
			<< "具体奖励/惩罚：" << reward._reward << std::endl;
		return out;
	}
	std::ostream& operator<<(std::ostream& out, celia::ResumeInfo& resume)
	{
		out << "所在学校：" << resume._school << std::endl\
			<< "入学时间：" << resume._join_time << std::endl\
			<< "学号：" << resume._school_flg << std::endl\
			<< "职务：" << resume._post << std::endl\
			<< "证明人：" << resume._witness << std::endl;
		return out;
	}
	std::ostream& operator<<(std::ostream& out, celia::TeachInfo& teach)
	{
		out << "课程名：" << teach._lesson_name << std::endl\
			<< "任课教师：" << teach._teacher << std::endl\
			<< "学期：" << teach._term << std::endl\
			<< "学生学号：" << teach._school_flg << std::endl\
			<< "成绩：" << teach._grade << std::endl;
		return out;
	}

	std::ostream& operator<<(std::ostream& out, celia::StuInfo& stu)
	{
		out << "家庭住址：" << stu._homeInfo._address << std::endl\
			<< "家庭电话：" << stu._homeInfo._family_phone << std::endl\
			<< "姓名：" << stu._personInfo._name << std::endl \
			<< "性别：" << GetGender(stu._personInfo._gender) << std::endl \
			<< "年龄：" << stu._personInfo._age << std::endl \
			<< "出生日期：" << stu._personInfo._birth << std::endl\
			<< "民族：" << stu._personInfo._nationality << std::endl\
			<< "籍贯：" << stu._personInfo._native_place << std::endl\
			<< "电话：" << stu._personInfo._phone << std::endl\
			<< "健康状态：" << GetHealth(stu._personInfo._health_state) << std::endl\
			<< "所在学校：" << stu._schInfo._school << std::endl\
			<< "入学时间：" << stu._schInfo._join_time << std::endl \
			<< "所在学院：" << stu._schInfo._college << std::endl \
			<< "所学专业：" << stu._schInfo._major << std::endl \
			<< "学号：" << stu._schInfo._school_flg << std::endl \
			<< "政治面貌：" << GetPolitical(stu._schInfo._political) << std::endl\
			<< "加入" << GetPolitical(stu._schInfo._political) << "时间：" << stu._schInfo._join_political_time << std::endl\
			<< "宿舍号：" << stu._schInfo._hostel_flg << std::endl\
			<< "宿舍电话：" << stu._schInfo._hostel_phone << std::endl\
			<< "职务：" << stu._schInfo._post << std::endl\
			<< "任职起始时间：" << stu._schInfo._post_time << std::endl;
		//各科成绩部分：
		std::cout << std::endl << "成绩部分：" << std::endl;
		for (auto x : stu._teachList)
		{
			std::cout << x << std::endl;
		}
		//奖惩部分（如果有）
		if (stu._rewardList.size())
		{
			std::cout << std::endl << "奖惩部分：" << std::endl;
			for (auto x : stu._rewardList)
			{
				std::cout << x;
			}
		}
		out << "================================================================" << std::endl;
		return out;
	}
}